package cate.game.pvp.eliterace.handler;

import cate.game.framework.common.compress.CompressedContent;
import cate.game.pvp.eliterace.data.EliteRaceOpponent;
import cate.game.pvp.eliterace.data.EliteRacePsData;
import cate.game.pvp.eliterace.data.EliteRacePs;
import cate.game.pvp.pointrace.data.PointRaceOpponent;
import cate.game.pvp.pointrace.data.PointRacePs;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import static cate.common.table.d.GDEliteRace.POINT_RACE_POINTS_RADIO;
import static cate.game.pvp.eliterace.data.EliteRacePs.INDEX_NAME;

public class BothEliteRacePsOperation implements EliteRacePsOperation {

    private final EliteRacePsData psData;
    private final Initializer initializer;

    public BothEliteRacePsOperation(Supplier<EliteRacePsData> psDataSupplier,
                                    Initializer initializer) {
        Objects.requireNonNull(psDataSupplier);
        this.psData = Objects.requireNonNull(psDataSupplier.get());
        this.initializer = Objects.requireNonNull(initializer);
    }

    @Override
    public boolean initialize() {
        if (psData.getValueList().isEmpty()) {
            List<PointRacePs> loadedPs = this.initializer.get();
            if (Objects.isNull(loadedPs) || loadedPs.isEmpty()) {
                return false;
            }

            AtomicInteger rank = new AtomicInteger(0);
            loadedPs.stream()
//                    .sorted(Comparator.comparing(PointRacePs::getOpponent, Comparator.comparing(PointRaceOpponent::getPoints, Comparator.reverseOrder())))
                    .map(ps -> EliteRacePs.of(ps, rank.incrementAndGet()))
                    .peek(ps -> ps.getOpponent().setPoints((long) Math.floor(ps.getOpponent().getPoints() * POINT_RACE_POINTS_RADIO)))
                    .peek(psData::addValue)
                    .forEach(eps -> psData.addIndex(INDEX_NAME, eps.getIndexKey(), eps));
        }
        return true;
    }

    @Override
    public EliteRacePs findOne(String uid) {
        if (!StringUtils.hasLength(uid)) {
            return null;
        }
        return psData.getIndex(INDEX_NAME).get(uid);
    }


    @Override
    public List<EliteRacePs> getSortedPs(Comparator<? super EliteRacePs> comparator) {
        return psData.getValueList()
                .stream()
                .sorted(comparator)
                .collect(Collectors.toList());
    }

    @Override
    public void update(EliteRacePs ps) {
        EliteRacePs eps = psData.getIndex(INDEX_NAME).get(ps.getUid());
        if (Objects.nonNull(eps)) {
            eps.getOpponent().setSnapshot(ps.getOpponent().getSnapshot().copy());
            LinkedList<CompressedContent> cpsList = eps.getCpsList();
            cpsList.addAll(ps.getCpsList());
        } else {
            psData.addValue(ps);
            psData.addIndex(INDEX_NAME, ps.getIndexKey(), ps);
        }
    }

    @Override
    public List<EliteRaceOpponent> query(int srvId) {
        Map<String, EliteRacePs> indexMap = psData.getIndex(INDEX_NAME);
        return indexMap.values()
                .stream()
                .map(EliteRacePs::getOpponent)
                .filter(opp -> opp.getSnapshot().base.srvId == srvId)
                .collect(Collectors.toList());
    }
}
